Skip to content

Conversation

@clavery
Copy link
Collaborator

@clavery clavery commented Jan 8, 2026

Summary

This PR introduces a unified configuration abstraction for the B2C SDK and adds a comprehensive plugin hook system for extending CLI functionality. The changes consolidate configuration loading logic, provide a consistent API across CLI and SDK consumers, and enable third-party plugins to inject configuration, middleware, lifecycle hooks, and custom cartridge discovery.

New Extensibility Hooks

Hook Purpose SDK Support
b2c:config-sources Custom configuration loading CLI only
b2c:http-middleware HTTP request/response middleware Yes
b2c:operation-lifecycle B2C operation before/after callbacks CLI only
b2c:cartridge-providers Custom cartridge discovery CLI only

HTTP Middleware Hook

Plugins can inject middleware into all HTTP clients (OCAPI, SLAS, WebDAV, etc.) for logging, metrics, custom headers, or request/response transformation.

const provider: HttpMiddlewareProvider = {
  name: 'request-logger',
  getMiddleware(clientType) {
    return {
      onRequest({ request }) {
        console.log(`[${clientType}] ${request.method} ${request.url}`);
        return request;
      },
    };
  },
};

B2C Operation Lifecycle Hook

Plugins can observe and control B2C operation execution with before/after callbacks. The context includes the full B2CInstance for API access.

const provider: B2COperationLifecycleProvider = {
  name: 'audit-logger',
  async beforeOperation(context) {
    // Access context.instance for API calls
    // Return { skip: true } to prevent execution
  },
  async afterOperation(context, result) {
    // Log results, send notifications, etc.
  },
};

Supported operations: job:run, job:import, job:export, code:deploy

Cartridge Providers Hook

Plugins can provide custom cartridge discovery logic (manifest files, remote sources, etc.).

const provider: CartridgeProvider = {
  name: 'manifest-provider',
  priority: 'before', // or 'after' default discovery
  async findCartridges(options) {
    // Return CartridgeMapping[] from custom source
  },
};

Configuration System

New Components

  • ConfigResolver - High-level API for resolving configuration from multiple sources
  • ConfigSource interface - Extensible protocol for custom config sources
  • Built-in sources: DwJsonSource (dw.json), MobifySource (~/.mobify)
  • NormalizedConfig - Canonical camelCase format for all configuration
  • Hostname mismatch protection - Prevents mixing credentials across instances

Resolution Priority

  1. CLI flags and environment variables (highest)
  2. Plugin sources with priority: 'before'
  3. dw.json configuration file
  4. ~/.mobify (MRT API key)
  5. Plugin sources with priority: 'after' (lowest)

SDK Changes

New Files

  • src/cli/lifecycle.ts - B2C operation lifecycle types and runner
  • src/cli/cartridge-providers.ts - Cartridge provider types and runner
  • src/clients/middleware-registry.ts - HTTP middleware registry (SDK-level)
  • src/config/resolver.ts - Configuration resolver
  • src/config/mapping.ts - Config format normalization
  • src/config/types.ts - Configuration type definitions

Updated Base Commands

  • JobCommand - Lifecycle hook support for job operations
  • CartridgeCommand - Lifecycle hooks + cartridge provider integration
  • BaseCommand - HTTP middleware and config source collection

HTTP Client Updates

All clients now support middleware from the global registry:

  • OCAPI, SLAS, ODS, MRT, Custom APIs - openapi-fetch middleware
  • WebDAV - Adapted fetch middleware pattern

Example Plugin

New package @salesforce/b2c-plugin-example-config demonstrating:

  • EnvFileSource - Loads configuration from .env.b2c files
  • Hook registration with priority ordering

Documentation

  • Updated: docs/guide/extending.md - Comprehensive plugin development guide covering all four hooks
  • Updated: docs/guide/configuration.md - Resolution priority with plugin sources

@clavery clavery force-pushed the feature/env-loading-consistency branch from 189dad3 to 782e21a Compare January 11, 2026 00:53
- Add b2c:config-sources hook for plugins to provide ConfigSource instances
- Support priority ordering (before/after default sources)
- Create example plugin demonstrating .env.b2c config loading
- Add documentation for extending the CLI with custom plugins
@clavery clavery changed the title [DRAFT] refactoring configuration loading Unified Configuration System with Plugin Extensibility Jan 11, 2026
@clavery clavery marked this pull request as ready for review January 11, 2026 03:17
@clavery clavery requested a review from yhsieh1 January 11, 2026 03:17
@clavery
Copy link
Collaborator Author

clavery commented Jan 11, 2026

@yhsieh1 This is a significant change in config. I've update the MCP services.ts to use the new strategy. I think it looks cleaner. The idea is that you send in all the the config and we let you create B2CInstances or MRT Auth Strategies from that but also let you check if we even can (config.hasMrtConfig() etc). So this allowed for cleanup of config specifics in the MCP package and now it's more future proof to configuration in the future (for instance this PR adds support for config plugins so developers can bring their own config sources like new file types)

Your services implementation is otherwise unchanged so I think everything should still work.

OAuth (clientId/clientSecret) and Basic auth (username/password) credentials
are now treated as atomic groups. If any field in a group is set by a
higher-priority source, all fields in that group from lower-priority sources
are skipped. This prevents accidentally mixing credentials that don't belong
together.
@clavery clavery changed the title Unified Configuration System with Plugin Extensibility Unified Configuration System with Plugin Extensibility Hooks Jan 12, 2026
@clavery clavery requested a review from yhsieh1 January 12, 2026 20:44
@yhsieh1
Copy link
Contributor

yhsieh1 commented Jan 12, 2026

It looks good overall but it seems there is check warning packages/b2c-cli/src/commands/job/run.ts
Line 69.
Check warning:
Async method 'run' has a complexity of 23. Maximum allowed is 20

@clavery
Copy link
Collaborator Author

clavery commented Jan 12, 2026

It looks good overall but it seems there is check warning packages/b2c-cli/src/commands/job/run.ts Line 69. Check warning: Async method 'run' has a complexity of 23. Maximum allowed is 20

We've had a few of these. Added a bug to fix them all #36

@clavery clavery merged commit b2e8910 into main Jan 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants